﻿using Prism.Commands;
using Prism.Navigation;
using Prism.Regions;
using Quartz;
using Quartz.Impl.Matchers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Data;

namespace ZYing.QPanel.ViewModels
{
    public class TriggersViewModel : NavigationViewModelBase
    {
        public TriggersViewModel(IScheduler scheduler)
        {
            Scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
            this.ReloadCommand = new DelegateCommand(RunReload);
            this.PauseJobCommand = new DelegateCommand<JobKey>(PauseJob);
            this.ResumeJobCommand = new DelegateCommand<JobKey>(ResumeJob);
            this.RunReload();
            var cvs = CollectionViewSource.GetDefaultView(this.Triggers);
            cvs.GroupDescriptions.Add(new PropertyGroupDescription("JobKey"));
            Run(this.CancellationTokenSource.Token);
        }

        public IScheduler Scheduler { get; }

        private string _keyword;

        public string Keyword
        {
            get { return _keyword; }
            set { if (SetProperty(ref _keyword, value)) this.RunReload(); }
        }
        private string _group;

        public string Group
        {
            get { return _group; }
            set { if (SetProperty(ref _group, value)) this.RunReload(); }
        }
        public ObservableCollection<string> Groups { get; } = new ObservableCollection<string>();
        public ObservableCollection<TriggerItemViewModel> Triggers { get; } = new ObservableCollection<TriggerItemViewModel>();
        private async void RunReload()
        {
            await Reload();
        }
        public DelegateCommand ReloadCommand { get; }
        public async Task Reload()
        {
            var groups = await Scheduler.GetTriggerGroupNames();
            foreach (var name in groups)
            {
                if (Groups.Contains(name)) continue;
                Groups.Add(name);
            }
            GroupMatcher<TriggerKey> matcher = GroupMatcher<TriggerKey>.AnyGroup();
            if (!string.IsNullOrWhiteSpace(this.Group)) matcher = GroupMatcher<TriggerKey>.GroupEquals(this.Group);
            var list = await GetAllTriggers(matcher, this.Keyword);
            var dic = this.Triggers.ToDictionary(i => i.Key, i => i);
            foreach (var item in list)
            {
                if (dic.TryGetValue(item.Key, out var job))
                {
                    dic.Remove(item.Key);
                    job.Merge(item);
                }
                else
                {
                    this.Triggers.Add(item);
                }
            }
            if (dic.Count > 0)
            {
                foreach (var item in dic.Values)
                {
                    this.Triggers.Remove(item);
                }
            }
        }
        private async Task<IReadOnlyList<TriggerItemViewModel>> GetAllTriggers(GroupMatcher<TriggerKey> matcher, string keyword)
        {
            if (matcher == null) matcher = GroupMatcher<TriggerKey>.AnyGroup();
            var ret = new List<TriggerItemViewModel>();
            var keys = await Scheduler.GetTriggerKeys(matcher);
            foreach (var key in keys)
            {
                if (!string.IsNullOrWhiteSpace(keyword))
                {
                    var str = $"{key.Name} {key.Group}";
                    if (str.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) < 0)
                    {
                        continue;
                    }
                }
                var triggerItem = new TriggerItemViewModel(key, this);
                await triggerItem.RefreshStatus();
                ret.Add(triggerItem);
            }
            return ret;
        }

        public async Task RefreshStatus()
        {
            //做一个拷贝，防止循环更新
            var triggers = this.Triggers.ToArray();
            foreach (var trigger in triggers)
            {
                await trigger.RefreshStatus();
            }
        }

        private async void Run(CancellationToken cancellationToken)
        {
            while (true)
            {
                if (cancellationToken.IsCancellationRequested) break;
                if (this.IsActive)
                {
                    try
                    {
                        await RefreshStatus();
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine(e);
                    }
                }
                await Task.Delay(1000);
            }
        }
        public async void PauseJob(JobKey jobKey)
        {
            if (jobKey == null) return;
            await this.Scheduler.PauseJob(jobKey);
            await this.RefreshStatus();
        }
        public async void ResumeJob(JobKey jobKey)
        {
            if (jobKey == null) return;
            await this.Scheduler.ResumeJob(jobKey);
            await this.RefreshStatus();
        }
        public DelegateCommand<JobKey> PauseJobCommand { get; }
        public DelegateCommand<JobKey> ResumeJobCommand { get; }
    }
}
